/******************************************************************************* * Copyright (c) 2002, 2013 Object Factory Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Object Factory Inc. - Initial implementation *******************************************************************************/ package org.eclipse.ant.internal.ui.dtd.util; import java.util.Comparator; /** * SortedSet is a flyweight set implementation that uses an external array provided by a KeyHolder. SortedSet provides both equality/comparison * operations and identity operations. * * @author Bob Foster */ public class SortedSet { protected Comparator<Object> fComp; protected IKeyHolder fKeyHolder; protected SortedSet fNext; public SortedSet(IKeyHolder holder, Comparator<Object> comp) { fComp = comp; fKeyHolder = holder; } /** * Constructor. A keyholder must be supplied by <code>setKeyHolder()</code> prior ot <i>any</i> operations. */ public SortedSet(Comparator<Object> comp) { fComp = comp; } /** * Constructor, no comparator. Only identity operations may be performed in this set. */ public SortedSet(IKeyHolder holder) { fKeyHolder = holder; } /** * Constructor, no comparator. Only identity operations may be performed in this set. A keyholder must be supplied by <code>setKeyHolder()</code> * prior ot <i>any</i> operations. */ public SortedSet() { } public void setKeyHolder(IKeyHolder holder) { fKeyHolder = holder; } public void setComparator(Comparator<Object> comp) { fComp = comp; } /** * Add to set (no duplicates allowed). * * @param obj * Object to add * @return true if object was added; false if object was already in the set. */ public boolean add(Object obj) { return internalAdd(obj, false) >= 0; } protected int internalAdd(Object obj, boolean always) { Object[] array = fKeyHolder.getKeys(); if (array == null) { array = new Object[1]; fKeyHolder.setKeys(array); array[0] = obj; return 0; } int i = 0; int comp = -1; for (; i < array.length; i++) { if ((comp = fComp.compare(obj, array[i])) <= 0) { break; } } if (comp == 0 && !always) return -1; internalAdd(i, obj); return i; } protected void internalAdd(int i, Object obj) { Object[] array = fKeyHolder.getKeys(); if (array == null) { array = new Object[1]; array[0] = obj; fKeyHolder.setKeys(array); } else { Object[] tmp = new Object[array.length + 1]; System.arraycopy(array, 0, tmp, 0, i); tmp[i] = obj; System.arraycopy(array, i, tmp, i + 1, array.length - i); fKeyHolder.setKeys(tmp); } } /** * Add allowing duplicates. * * @param obj * Object to add * @return index where object was added in sorted order. */ public int addAlways(Object obj) { return internalAdd(obj, true); } /** * Append, a variant of add allowing duplicates that always puts the new member at the end of the set. Set can be used with identity operations * only. */ public void append(Object obj) { Object[] array = fKeyHolder.getKeys(); int len = array != null ? array.length : 0; internalAdd(len, obj); } public boolean contains(Object obj) { return indexOf(obj) >= 0; } public int indexOf(Object obj) { Object[] array = fKeyHolder.getKeys(); if (array == null) return -1; for (int i = 0; i < array.length; i++) { int comp = fComp.compare(obj, array[i]); if (comp == 0) return i; if (comp < 0) return -1; } return -1; } public boolean containsIdentity(Object obj) { return indexOf(obj) >= 0; } public int indexOfIdentity(Object obj) { Object[] array = fKeyHolder.getKeys(); if (array == null) return -1; for (int i = 0; i < array.length; i++) { if (obj == array[i]) return i; } return -1; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof SortedSet)) return false; SortedSet other = (SortedSet) o; Object[] array = fKeyHolder.getKeys(); Object[] otherarray = other.fKeyHolder.getKeys(); if ((array == null) != (otherarray == null)) return false; if (array == null) return true; if (array.length != otherarray.length) return false; for (int i = 0; i < array.length; i++) { if (array[i] != otherarray[i]) return false; } return true; } public void merge(SortedSet other) { Object[] array = fKeyHolder.getKeys(); Object[] otherarray = other.fKeyHolder.getKeys(); if (otherarray == null) return; if (array == null) { array = otherarray; return; } int ithis = 0, iother = 0, i = 0; int mthis = array.length, mother = otherarray.length; Object[] tmp = new Object[mthis + mother]; while (ithis < mthis && iother < mother) { int comp = fComp.compare(array[ithis], otherarray[iother]); if (comp <= 0) { tmp[i++] = array[ithis++]; } else { tmp[i++] = otherarray[iother++]; } } while (ithis < mthis) { tmp[i++] = array[ithis++]; } while (iother < mother) { tmp[i++] = otherarray[iother++]; } } public Object[] members() { Object[] array = fKeyHolder.getKeys(); if (array == null) return new Object[0]; return array; } public int size() { Object[] array = fKeyHolder.getKeys(); return array == null ? 0 : array.length; } public void remove(int i) { Object[] array = fKeyHolder.getKeys(); Object[] tmp = new Object[array.length - 1]; System.arraycopy(array, 0, tmp, 0, i); System.arraycopy(array, i + 1, tmp, i, array.length - i - 1); fKeyHolder.setKeys(tmp); } public boolean remove(Object obj) { int i = indexOf(obj); if (i >= 0) { remove(i); return true; } return false; } public boolean removeIdentity(Object obj) { int i = indexOfIdentity(obj); if (i >= 0) { remove(i); return true; } return false; } public SortedSet getNextSet() { return fNext; } public void setNextSet(SortedSet next) { fNext = next; } }